package com.lanyou.esb.web;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.Part;
import javax.wsdl.WSDLException;

import org.apache.catalina.core.ApplicationPart;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.lanyou.cook.common.Constants;
import com.lanyou.cook.datadictionary.UserLogOpt;
import com.lanyou.cook.entity.domain.FieldSystem;
import com.lanyou.cook.entity.domain.ParamSetting;
import com.lanyou.cook.paramsetting.ParamSettingReppository;
import com.lanyou.cook.repository.FieldSystemRepository;
import com.lanyou.cook.service.UserLogService;
import com.lanyou.cook.service.security.UserSessionService;
import com.lanyou.cook.util.gson.GsonUtil;
import com.lanyou.esb.common.CommonUtils;
import com.lanyou.esb.datadictionary.EnableType;
import com.lanyou.esb.entity.WsdlMetaData;
import com.lanyou.esb.entity.WsdlMetaDataDetail;
import com.lanyou.esb.exception.ServiceHandlerException;
import com.lanyou.esb.repository.WsdlMetaDataDetailRepository;
import com.lanyou.esb.repository.WsdlMetaDataRepository;
import com.lanyou.esb.service.WsdlMetaDataService;
import com.lanyou.esb.util.FileUploadCilent;
import com.lanyou.esb.web.param.WsdlMetaDataParam;
import com.primeton.esb.sam.wsdl.WSDLToSoap;


@RestController
@RequestMapping(Constants.BASE_URL_API + "/wsdlMetaDatas")
public class WsdlMetaDataController {

	@Autowired
    private WsdlMetaDataService  wsdlMetaDataService;
	
	@Autowired
	private UserSessionService userSessionService;
	
	@Autowired
	private WsdlMetaDataRepository wsdlMetaDataRepository;  
	
	@Autowired
	private WsdlMetaDataDetailRepository wsdlMetaDataDetailRepository; 
	
	@Autowired
	private FieldSystemRepository fieldSystemRepository;
	
	
	@Autowired
	private UserLogService userLogService;
	
	@Autowired
	private ParamSettingReppository paramSettingReppository;
    
	
	/**
	 * 查询元数据列表
	 * @param param	查询条件实体
	 * @param pageable	分页实体
	 * @return
	 */
	@RequestMapping("/search/findByExample")
	@RequiresPermissions(value={"metaDataManagement"})
	public Page<WsdlMetaData> findByExample(WsdlMetaDataParam param, Pageable pageable) {
		
		Specification<WsdlMetaData> spec = new Specification<WsdlMetaData>() {
			@Override
			public Predicate toPredicate(Root<WsdlMetaData> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				List<Predicate> predicatesList = new ArrayList<>();
				if(StringUtils.isNotBlank(param.getWsdlAddress())){
					predicatesList.add(cb.like(root.get("wsdlAddress"), '%' +param.getWsdlAddress() + '%'));
				}
				
				if(StringUtils.isNotBlank(param.getWsdlFilePath())){
					predicatesList.add(cb.like(root.get("wsdlFilePath"), '%' +param.getWsdlFilePath() + '%'));
				}
				
				// 领域系统
				Path<String> pathOwnerFieldSystemId = root.get("ownerFieldSystem").get("id");
				if(StringUtils.isNotBlank(param.getFieldSystemId())){
					predicatesList.add(cb.equal(pathOwnerFieldSystemId, param.getFieldSystemId()));
				} else {
					// 默认查当前登录用户所管理的领域系统
					Collection<String> fieldSystemIds = userSessionService.findFieldSystemIdsOfCurrentAuthenticatedUserCanManage();
					if(!CollectionUtils.isEmpty(fieldSystemIds)){
						predicatesList.add(pathOwnerFieldSystemId.in(fieldSystemIds));
					}else {
						predicatesList.add(cb.notEqual(cb.literal(1), 1));
					}
				}
				
				// 领域
				if(StringUtils.isNotBlank(param.getFieldId())){
					predicatesList.add(cb.equal(root.get("ownerFieldSystem").get("field").get("id"), param.getFieldId()));
				}
				
				query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
				return null;
			}
		};
		
		return wsdlMetaDataRepository.findAll(spec, pageable);
	}
	
	
	/**
	 * 获取所有的接口编码
	 * @param wsdlURL	wsdl地址
	 * @return
	 */
    @RequestMapping(value="/wsdlImportByUrl", produces="application/json")
    @RequiresPermissions(value={"metaDataManagement"})
    public String wsdlImportByUrl(String wsdlURL) {
    	
    	JsonObject jsonObject = new JsonObject();
		String wsdlOperations = "";
		try {
			wsdlOperations = wsdlMetaDataService.getInterfaceCodes(wsdlURL);
		}catch(WSDLException e){
			e.printStackTrace();
			jsonObject.addProperty("backValue", false);
			jsonObject.addProperty("errorDes", "wsdl地址无法访问，请确认网络是否能正常连接以及地址是否填写正确！");
			return jsonObject.toString();
		}catch (Exception e) {
			jsonObject.addProperty("backValue", false);
			jsonObject.addProperty("errorDes", "服务异常，获取接口编码失败，请稍后重试或联系管理员！");
			return jsonObject.toString();
		}
            
		jsonObject.addProperty("backValue", true);
    	jsonObject.addProperty("wsdlOperations", wsdlOperations);
    	return jsonObject.toString();
    }
    
    /**
     * 获取webservice的请求报文
     * @param wsdlURL
     * @param operation
     * @return
     */
    @RequestMapping(value="/getSoapRequestMsg", produces="application/json")
    @RequiresPermissions(value={"metaDataManagement"})
    public String getSoapRequestMsg(String wsdlURL, String operation) {
    	JsonObject jsonObject = new JsonObject();
    	if(StringUtils.isNotBlank(operation)){
    		String soapRequestMsg = "";
			try {
				soapRequestMsg = wsdlMetaDataService.getSoapRequestMsg(wsdlURL, operation);
				jsonObject.addProperty("backValue", true);
	    		jsonObject.addProperty("soapRequestMsg", soapRequestMsg);
			} catch (Exception e) {
				e.printStackTrace();
				jsonObject.addProperty("backValue", false);
			}
    		
    	}else{
    		jsonObject.addProperty("backValue", false);
    	}
    	
    	return jsonObject.toString();
    }
    
    /**
     * 获取接口返回报文
     * @param wsdlURL
     * @param operation
     * @param requestBody
     * @param soapProtocol
     * @return
     * @throws HttpException
     * @throws IOException
     */
    @RequestMapping(value="/getSoapReponsetMsg", produces="application/json")
    @RequiresPermissions(value={"metaDataManagement"})
    public String getSoapReponsetMsg(String wsdlURL, String operation, String requestBody, String soapProtocol) throws HttpException, IOException {
    	
    	return wsdlMetaDataService.getSoapReponsetMsg(wsdlURL, operation, requestBody, soapProtocol);
		
    }
    
    /**
     * 发布wsdl元数据
     * @param wsdlURL	wsdl地址
     * @param fieldSystemId	系统ID
     * @return
     */
	@RequestMapping(value = "/wsdlMetaDataSave", produces = "application/json")
	@RequiresPermissions(value={"metaDataManagement"})
	@Transactional
	public String wsdlMetaDataSave(String wsdlURL, String fieldSystemId) {
		
		String proPath = getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
		String filePath = "";
		if(proPath.lastIndexOf("/lib") != -1){
			filePath  = proPath.substring(0, proPath.lastIndexOf("/lib"));
		}else{
			filePath  = proPath.substring(0, proPath.length() - 5);
		}
		
		//System.out.println("s:" + filePath);
		JsonObject result = new JsonObject();
		WsdlMetaData findWsdlMetaData = wsdlMetaDataRepository.findByWsdlAddress(wsdlURL);
		if(findWsdlMetaData != null){
			result.addProperty("backValue", false);
			result.addProperty("errorDes", "当前要保存的wsdl地址已存在！");
			return result.toString();
		}
		WsdlMetaData wsdlMetaData = new WsdlMetaData();
		wsdlMetaData.setWsdlAddress(wsdlURL);
		
		System.out.println(wsdlURL.lastIndexOf("/") + ":" + wsdlURL.lastIndexOf("?"));
		String wsdlFileName = wsdlURL.substring(wsdlURL.lastIndexOf("/") + 1, wsdlURL.lastIndexOf("?"));
		String operationData = "";
		try{
			SAXReader reader = new SAXReader(); 
			Document document = reader.read(wsdlURL);
			Element root=document.getRootElement(); 
			
			ParamSetting paramSettingServer = paramSettingReppository
					.findByParamName(Constants.SERVERMIX_SERVER);
			
			if(paramSettingServer == null){
				//抛出异常
				result.addProperty("backValue", false);
				result.addProperty("errorDes", "发布失败，" + CommonUtils.MSG_NONE_SERVICE_MIX_SETTING);
				return result.toString();
			}
			
			JsonArray jsonDatas = GsonUtil.getDefaultJsonParser()
					.parse(paramSettingServer.getParamValue()).getAsJsonArray();
			
			for (JsonElement jsonElement : jsonDatas) {
				String ip = jsonElement.getAsJsonObject().get("ip").getAsString();
				String socketUploadPort = jsonElement.getAsJsonObject().get("SocketUploadPort").getAsString();
				
				File file = new File(filePath + "/temp");
				File file1 = new File(filePath + "/temp/" + wsdlFileName + ".wsdl");
				if(!file.exists()){
					file.mkdir();
				}
				
				InputStream in = null;
				if(!file1.exists()){
					//不存在文件
					OutputStream out = null;
					file1.createNewFile();
					out = new FileOutputStream(file1);
					out.write(root.asXML().getBytes());
					out.close();
				}else{
					//存在文件
				}
				in = new FileInputStream(file1);
				FileUploadCilent.uploadBundleBySocketForWsdl(ip, socketUploadPort, root.asXML().length(), wsdlFileName + ".wsdl", in);
			}
			
			
			wsdlMetaData.setWsdlFilePath(Constants.INSTALL_BUNDLE_SERVER_PATH + "/temp/" + wsdlFileName + ".wsdl");
			
			FieldSystem fieldSystem = fieldSystemRepository.findOne(FieldSystem.idSpecification(fieldSystemId));
			
			wsdlMetaData.setOwnerFieldSystem(fieldSystem);
			wsdlMetaData.setIsEnable(EnableType.ENABLE.ValueCode);
			wsdlMetaDataRepository.save(Arrays.asList(wsdlMetaData));
	
			operationData = wsdlMetaDataService.getInterfaceCodes(wsdlURL);
		} catch (WSDLException e) {
			result.addProperty("backValue", false);
			result.addProperty("errorDes", "发布失败，wsdl地址不正确");
			return result.toString();
		} catch (Exception e) {
			e.printStackTrace();
			result.addProperty("backValue", false);
			result.addProperty("errorDes", "发布失败！");
			return result.toString();
			
		}


		if (StringUtils.isNotEmpty(operationData)) {
			WsdlMetaData wsdlMetaData1 = wsdlMetaDataRepository.findByWsdlAddress(wsdlURL);
			if(operationData.contains(",")){
				String[] operation = operationData.split(",");
				for (int i = 0; i < operation.length; i++) {
					WsdlMetaDataDetail wsdlMetaDataDetail = new WsdlMetaDataDetail();
					wsdlMetaDataDetail.setInterfaceMethod(operation[i]);
					String soapMessage = WSDLToSoap.getSoapMessage(wsdlURL, operation[i]);
					wsdlMetaDataDetail.setInterfaceRequestMsg(soapMessage);
					wsdlMetaDataDetail.setWsdlMetaData(wsdlMetaData1);
					wsdlMetaDataDetail.setIsEnable(EnableType.ENABLE.ValueCode);
					wsdlMetaDataDetailRepository.save(Arrays.asList(wsdlMetaDataDetail));
				}
			}else{
				WsdlMetaDataDetail wsdlMetaDataDetail = new WsdlMetaDataDetail();
				wsdlMetaDataDetail.setInterfaceMethod(operationData);
				String soapMessage = WSDLToSoap.getSoapMessage(wsdlURL, operationData);
				wsdlMetaDataDetail.setInterfaceRequestMsg(soapMessage);
				wsdlMetaDataDetail.setIsEnable(EnableType.ENABLE.ValueCode);
				wsdlMetaDataDetail.setWsdlMetaData(wsdlMetaData1);
				wsdlMetaDataDetailRepository.save(Arrays.asList(wsdlMetaDataDetail));
			}
		}
		
		result.addProperty("backValue", true);
		
		userLogService.save(UserLogOpt.MaintenanceServiceRegister, null, String.format("保存了接口测试地址：“%s”", wsdlURL));
		return result.toString();

	}

}
